package com.sip.dbadapter.dao.impl;

import java.io.Serializable;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

import org.hibernate.HibernateException;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Restrictions;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.support.DataAccessUtils;
import org.springframework.orm.hibernate3.HibernateCallback;
import org.springframework.orm.hibernate3.HibernateTemplate;

import com.sip.dbadapter.dao.base.BaseDao;
import com.sip.dbadapter.dao.exception.CustomException;

public abstract class BusinessDaoImpl<T, PK extends Serializable> implements BaseDao<T, PK> {

    private static final String DATA_ACCESS_EXCEPTION_IN_FIND = "DataAccessException in  Find";

    @Autowired
    private HibernateTemplate hibernateTemplate;

    protected Class<T> domainClass = getDomainClass();

    protected abstract Class<T> getDomainClass();

    public HibernateTemplate getHibernateTemplate() throws Exception {

        return hibernateTemplate;
    }

    public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {

        this.hibernateTemplate = hibernateTemplate;

    }

    @SuppressWarnings("unchecked")
    public Serializable save(T t) {

        return hibernateTemplate.save(t);
   
     
    }

    @SuppressWarnings("unchecked")
    public void update(T t) {

        hibernateTemplate.update(t);
    }
    
    @SuppressWarnings("unchecked")
    public void saveOrUpdate(T t) {

        hibernateTemplate.saveOrUpdate(t);
    }
    
    @SuppressWarnings("unchecked")
    public void saveOrUpdateAll(List<T> t) {

        hibernateTemplate.saveOrUpdateAll(t);
    }
  

    @SuppressWarnings("unchecked")
    public void delete(T t) {

        hibernateTemplate.delete(t);
    }

    @SuppressWarnings("unchecked")
    public List<T> find() throws CustomException {

        List<T> t = new ArrayList<T>();
        try {
            t = getHibernateTemplate().find("from " + getDomainClass().getName());
        } catch (DataAccessException e) {
            throw new CustomException(DATA_ACCESS_EXCEPTION_IN_FIND+"Error=>"+e.toString(),0001);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;
    }

    @SuppressWarnings("unchecked")
    public List<T> find(String domainObjectField, Object value) throws CustomException {

        List<T> t = new ArrayList<T>();
        DetachedCriteria criteria = createDetachedCriteria();

        criteria.add(Restrictions.eq(domainObjectField, value));

        try {
            t = getHibernateTemplate().findByCriteria(criteria);
        } catch (DataAccessException e) {
            throw new CustomException(DATA_ACCESS_EXCEPTION_IN_FIND+"Error=>"+e.toString(),0001);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return t;

    }

    @SuppressWarnings("unchecked")
    public T findById(PK id) throws CustomException {

        T t = null;
        try {
        
            t = getHibernateTemplate().get(getDomainClass(), id);
        } catch (Exception e) {
            throw new CustomException(DATA_ACCESS_EXCEPTION_IN_FIND+"Error"+e.toString(),0001);
        }
        return t;
    }

    /**
  * 
  */
    public T search(final String columnName, final Object value) {

        return hibernateTemplate.execute(new HibernateCallback<T>() {

            public T doInHibernate(Session session) throws HibernateException, SQLException {

                return DataAccessUtils.objectResult(session.createCriteria(getDomainClass()).add(Restrictions.eq(columnName, value)).list(),
                    getDomainClass());
            }
        });
    }

    /**
     * @param query
     * @return
     */
    public Object exec(final String query) {

        return hibernateTemplate.execute(new HibernateCallback<Object>() {

            public Object doInHibernate(Session session) throws HibernateException, SQLException {

                return session.createQuery(query).list();
            }

        });
    }
    
    public Object exec(final String query, final Object[] params) {
        
        System.out.println("Query====================>"+query);
        return  hibernateTemplate.execute(new HibernateCallback<Object>() {
            public Object doInHibernate(Session session)
                    throws HibernateException {

                Query q = session.createQuery(query);
                fillParams(q,params);
                return q.list();
                
            }
        });
    }
    


    /**
     * @return
     */
    protected DetachedCriteria createDetachedCriteria() {

        return DetachedCriteria.forClass(getDomainClass());

    }
    
    private void fillParams(Query q, final Object[] params) {

        if (null != params) {

            for (int i = 0; i < params.length; i++) {
                q.setParameter(i, params[i]);

            }
        }
    }

}
